﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SqlLiteTest
{
    public partial class Form1 : Form
    {
        static Form1 instance;
        string[] male_firstnames = "Michael,Christopher,Joshua,Matthew,Daniel,David,Andrew,Justin,Ryan,Robert,James,Nicholas,Joseph,John,Jonathan,Kevin,Kyle,Brandon,William,Eric,Jose,Steven,Jacob,Brian,Tyler,Zachary,Aaron,Alexander,Adam,Thomas,Richard,Timothy,Benjamin,Jason,Jeffrey,Sean,Jordan,Jeremy,Travis,Cody,Nathan,Mark,Jesse,Charles,Juan,Samuel,Patrick,Dustin,Scott,Stephen,Paul,Bryan,Luis,Derek,Austin,Kenneth,Carlos,Gregory,Alex,Cameron,Jared,Jesus,Bradley,Christian,Corey,Victor,Cory,Miguel,Tylor,Edward,Francisco,Trevor,Adrian,Jorge,Ian,Antonio,Shawn,Ricardo,Vincent,Edgar,Erik,Peter,Shane,Evan,Chad,Alejandro,Brett,Gabriel,Eduardo,Raymond,Phillip,Mario,Marcus,Manuel,George,Martin,Spencer,Garrett,Casey".Split(',');
        string[] female_firstnames = "Jessica,Ashley,Amanda,Brittany,Sarrah,Jennifer,Stephanie,Samantha,Elizabeth,Megan,Nicole,Lauren,Melissa,Amber,Michelle,Heather,Christina,Rachel,Tiffany,Kayla,Danielle,Vanessa,Rebecca,Laura,Courtney,Katherine,Chelsea,Kimberly,Sara,Kelsey,Andrea,Alyssa,Crystal,Maria,Amy,Alexandra,Erica,Jasmine,Natalie,Hanna,Angela,Kelly,Brittney,Mary,Cassandra,Erin,Victoria,Jacqueline,Jamie,Lindsey,Alicia,Lisa,Katie,Allison,Kristen,Cynthia,Anna,Caitlin,Monica,Christine,Diana,Erika,Veronica,Kathryn,Whitney,Brianna,Nancy,Shannon,Kristina,Lindsay,Kristin,Marissa,Patricia,Brooke,Brenda,Angelica,Morgan,Adriana,April,Ana,Taylor,Tara,Jordan,Jenna,Catherine,Alexis,Karen,Melanie,Natasha,Sandra,Julie,Bianca,Krystal,Mayra,Holly,Alexandria,Monique,Leslie,Katelyn".Split(',');
        string[] lastnames = "Smith,Johnson,Williams,Jones,Brown,Davis,Miller,Wilson,Moore,Taylor,Anderson,Thomas,Jackson,White,Harris,Martin,Thompson,Garcia,Martinez,Robinson,Clark,Rodriguez,Lewis,Lee,Walker,Hall,Allen,Young,Hernandez,King,Wright,Lopez,Hill,Scott,Green,Adams,Baker,Gonzalez,Nelson,Carter,Mitchell,Perez,Roberts,Turner,Phillips,Campbell,Parker,Evans,Edwards,Collins,Stewart,Sanchez,Morris,Rogers,Reed,Cook,Morgan,Bell,Murphy,Bailey,Rivera,Cooper,Richardson,Cox,Howard,Ward,Torres,Peterson,Gray,Ramirez,James,Watson,Brooks,Kelly,Sanders,Price,Bennett,Wood,Barnes,Ross,Henderson,Coleman,Jenkins,Perry,Powell,Long,Patterson,Hughes,Flores,Washington,Butler,Simmons,Foster,Gonzales,Bryant,Alexander,Russell,Griffin,Diaz,Hayes".Split(',');
        string[] states = "Alabama,Alaska,Arizona,Arkansas,California,Colorado,Connecticut,Delaware,Florida,Georgia,Hawaii,Idaho,Illinois,Indiana,Iowa,Kansas,Kentucky,Louisiana,Maine,Maryland,Massachusetts,Michigan,Minnesota,Mississippi,Missouri,Montana,Nebraska,Nevada,New Hampshire,New Jersey,New Mexico,New York,North Carolina,North Dakota,Ohio,Oklahoma,Oregon,Pennsylvania,Rhode Island,South Carolina,South Dakota,Tennessee,Texas,Utah,Vermont,Virginia,Washington,West Virginia,Wisconsin".Split(',');
        const int ADD_INDIVIDUALS_COUNT = 100;
              
        Random ran = new Random(0);

        private string[] Split(ref string s)
        {
            var names = new List<string>();
            var len = s.Length;
            for (int i = 0; i < len; i++)
            {
                var c = s[i];
                if (char.IsLetter(c))
                {
                    int from = i;
                    while (char.IsLetter(c) && i < len)
                    {
                        i++;
                        c = s[i];
                    }
                    names.Add(s.Substring(from, i - from));
                }
            }
            return names.ToArray();
        }

        public Form1()
        {
            instance = this;
            foreach (var fi in new System.IO.DirectoryInfo(".").GetFiles("*.ndx"))
            {
                fi.Delete();
            }

            InitializeComponent();
        }

        private string RandomEntry(string[] strings)
        {
            return strings[ran.Next(strings.Length)];
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (rbDbfDotNet.Checked || rbAll.Checked)
            {
                var db = new DbfDotNetDatabase();
                RunTests(db);
            }
            if (rbSqlite.Checked || rbAll.Checked)
            {
                var db = new SqliteDatabase();
                RunTests(db);
            }
        }

        static void Log(string s)
        {
            instance.textBox1.AppendText(s + "\n");
        }

        const int NB_INDIVIDUALS = 1000;

        private class ShowDuration : IDisposable
        {
            private string mMsg;
            private System.Diagnostics.Stopwatch mStopWatch;

            public ShowDuration(string msg)
            {
                mMsg = msg;
                mStopWatch = System.Diagnostics.Stopwatch.StartNew();
            }

            void IDisposable.Dispose()
            {
                Log(string.Format("{0}: {1} ms", mMsg, 1000 * mStopWatch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency));
            }
        }

        void RunTests(ITestDatabase db)
        {
            ran = new Random(0);
            string dbname = db.GetType().Name;

            using (new ShowDuration(string.Format("{0} Total", dbname)))
            {

                using (new ShowDuration(string.Format("Opening {0}", dbname)))
                {
                    db.OpenAndClear();
                    db.CreateIndividualTable();
                }

                using (new ShowDuration(string.Format("Insert {0} individuals", NB_INDIVIDUALS)))
                {
                    ran = new Random(1);
                    for (int i = 0; i < NB_INDIVIDUALS; i++)
                    {
                        int id = i;
                        bool male = (ran.NextDouble() > 0.5);
                        string firstname = RandomEntry(male ? male_firstnames : female_firstnames);
                        string middlename = RandomEntry(male ? male_firstnames : female_firstnames);
                        if (middlename == firstname) middlename = null;
                        string lastname = RandomEntry(lastnames);
                        DateTime dob = DateTime.Today.Subtract(new TimeSpan(ran.Next(36500), 0, 0, 0));
                        string state = RandomEntry(states);

                        db.InsertNewIndividual(id, firstname, middlename, lastname, dob, state);
                    }
                }

                using (new ShowDuration(string.Format("Read individuals sequentially", NB_INDIVIDUALS)))
                {
                    for (int j = 0; j < 10; j++)
                    {
                        for (int i = 0; i < NB_INDIVIDUALS; i++)
                        {
                            IIndividual indiv = db.GetIndividualById(i);
                        }
                    }
                }

                using (new ShowDuration(string.Format("Read individual randomly", NB_INDIVIDUALS)))
                {
                    for (int j = 0; j < 10; j++)
                    {
                        for (int i = 0; i < NB_INDIVIDUALS; i++)
                        {
                            IIndividual indiv = db.GetIndividualById(ran.Next(NB_INDIVIDUALS));
                        }
                    }
                }

                using (new ShowDuration(string.Format("Modifying individuals", NB_INDIVIDUALS)))
                {
                    db.BeginUpdates();
                    for (int i = 0; i < NB_INDIVIDUALS; i++)
                    {
                        IIndividual indiv = db.GetIndividualById(i);
                        if (indiv != null)
                        {
                            indiv.Dob = indiv.Dob.AddDays(1);
                            db.SaveIndividual(indiv);
                        }
                    }
                    db.EndUpdates();
                }

                using (new ShowDuration("Create DateOfBirth index"))
                {
                    db.CreateDobIndex();
                }

                using (new ShowDuration("Enumerate Individuals by age"))
                {
                    int cpt = 0;
                    foreach (IIndividual indiv in db.IndividualsByAge())
                    {
                        if (cpt < 5)
                        {
                            Log(string.Format("     {0} {1} {2}", indiv.FirstName, indiv.LastName, indiv.Dob.ToShortDateString()));
                        }
                        cpt++;
                    }
                    Log(String.Format("     ... total {0} records", cpt));
                }

                using (new ShowDuration(string.Format("Closing {0}", dbname)))
                {
                    db.Close();
                }
            }
            Log("");
        }

        

    }
}


//private Individual GetIndividualByRow(UInt32 rowNo)
//{
//    Individual individual = null;
//    if (mIndex == null)
//    {
//        individual = individuals.GetRecord(rowNo);
//    }
//    else
//    {
//        individual = mIndex.GetRecord(rowNo);
//    }
//    return individual;
//}

//void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
//{
//    var listviewItem = new ListViewItem();
//    Individual individual = GetIndividualByRow((UInt32)e.ItemIndex);
//    if (individual == null)
//    {
//        listviewItem.Text = "#null";
//        listviewItem.SubItems.Add("#null");
//        listviewItem.SubItems.Add("#null");
//        listviewItem.SubItems.Add("#null");
//        listviewItem.SubItems.Add("#null");
//        listviewItem.SubItems.Add("#null");
//    }
//    else
//    {
//        listviewItem.Text = "#" + (e.ItemIndex + 1);
//        listviewItem.SubItems.Add(individual.FIRSTNAME);
//        listviewItem.SubItems.Add(individual.MIDDLENAME);
//        listviewItem.SubItems.Add(individual.LASTNAME);
//        listviewItem.SubItems.Add(individual.DOB.ToShortDateString());
//        listviewItem.SubItems.Add(individual.STATE);
//    }
//    e.Item = listviewItem;
//}

//DateTime mLastRefresh;

//private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
//{
//    if (DateTime.Now.Subtract(mLastRefresh).TotalSeconds >= 5)
//    {
//        RefreshGrid();
//        mLastRefresh = DateTime.Now;
//    }
//    toolStripStatusLabel1.Text = string.Format("{0}% ({1} records)", e.ProgressPercentage, individuals.RecordCount);
//}

//private void RefreshBar()
//{
//    toolStripStatusLabel1.Text = string.Format("Ready ({0} records in database).", individuals.RecordCount);
//}

//private void RefreshGrid()
//{
//    listView1.VirtualListSize = 0;
//    listView1.VirtualListSize = individuals.RecordCount;
//}

//private void Form1_FormClosed(object sender, FormClosedEventArgs e)
//{
//    individuals.Close();
//}

//private void addToolStripMenuItem_Click(object sender, EventArgs e)
//{
//    int k = individuals.RecordCount;
//    for (int i = 0; i < ADD_INDIVIDUALS_COUNT; i++)
//    {
//        var newIndiv = individuals.NewRecord();
//        bool male = (ran.NextDouble() > 0.5);
//        string[] firsntnames = (male ? male_firstnames : female_firstnames);
//        newIndiv.FIRSTNAME = RandomEntry(firsntnames);
//        string middleName = RandomEntry(firsntnames);
//        if (middleName != newIndiv.FIRSTNAME)
//            newIndiv.MIDDLENAME = middleName;
//        newIndiv.LASTNAME = RandomEntry(lastnames);
//        newIndiv.STATE = RandomEntry(states);
//        newIndiv.DOB = DateTime.Today.Subtract(new TimeSpan(ran.Next(36500), 0, 0, 0));
//        k++;
//        newIndiv.SaveChanges();
//    }
//    RefreshBar();
//    RefreshGrid();
//}

//private void clearFileToolStripMenuItem_Click(object sender, EventArgs e)
//{
//    individuals.EmptyTable();
//    listView1.BeginUpdate();
//    RefreshGrid();
//    listView1.EndUpdate();
//    RefreshBar();
//}

//private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
//{
//    e.DrawDefault = true;
//}

//private void listView1_ColumnReordered(object sender, ColumnReorderedEventArgs e)
//{

//}

//private void listView1_SearchForVirtualItem(object sender, SearchForVirtualItemEventArgs e)
//{

//}

//private void listView1_Click(object sender, EventArgs e)
//{

//}

//private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
//{
//    if (e.Column == 0) mIndex = null;
//    else SetIndex(individuals.Columns[e.Column].mFieldInfo.Name);
//}

////private DbfIndex<Individual> mIndex;

//private void SetIndex(string columnName)
//{
//    var sortOrder = new SortOrder<Individual>(false);
//    sortOrder.AddField(columnName);
//    mIndex = individuals.GetIndex(columnName + ".ndx", sortOrder);
//    RefreshGrid();
//}

//private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
//{
//    e.DrawDefault = true;
//}

//private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
//{
//    e.DrawDefault = true;
//}

//private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
//{
//    var individual = GetIndividualByRow((UInt32)listView1.FocusedItem.Index);
//    var detailForm = new DetailForm();
//    detailForm.ReadIndividual(individual);
//    if (detailForm.ShowDialog() == DialogResult.OK)
//    {
//        detailForm.WriteIndividual(individual);
//        individual.SaveChanges();
//    }
//}
